//################################################################################
// MIT License
// Copyright (c) 2024 ZhangYihua
//
// Change Logs:
// Date           Author       Notes
// 2020-07-15     ZhangYihua   first version
//
// Description  : 
//################################################################################

module afifo_sync_cfg #(
parameter           DEPTH                   = 32,
parameter           PREFETCH_CNT_BW         = 1,        // prefetch cnt bit-width
parameter           SYNC_NUM_W2R            = 3,
parameter           SYNC_NUM_R2W            = 3,
//parameter           CPU_DOMAIN              = "CLK_WR",
parameter           CPU_DOMAIN              = "CLK_RD",

// the following parameters are calculated automatically
parameter           ADDR_BW                 = $clog2(DEPTH),    // address range [0:DEPTH-1]
parameter           CNT_BW                  = $clog2(DEPTH+1)   // fifo_cnt   range [0:DEPTH]
) ( 
input                                       rst_wr_n,
input                                       clk_wr,

input                                       rst_rd_n,
input                                       clk_rd,

// configuration to fifo module, and status from fifo module
output              [ADDR_BW-1:0]           fifo_afull_th,
output              [ADDR_BW-1:0]           fifo_aempty_th,

input                                       fifo_full,
input                                       fifo_afull,
input               [CNT_BW-1:0]            fifo_wcnt,
input                                       fifo_wilf,
input                                       fifo_wof,

input                                       fifo_empty,
input                                       fifo_aempty,
input               [CNT_BW-1:0]            fifo_rcnt,
input               [PREFETCH_CNT_BW-1:0]   prefetch_cnt,
input                                       fifo_rilf,
input                                       fifo_ruf,

// configuration from CPU bus, and status to CPU bus
input               [ADDR_BW-1:0]           cfg_fifo_afull_th,
input               [ADDR_BW-1:0]           cfg_fifo_aempty_th,

output              [CNT_BW-1:0]            sts_fifo_cnt,
output              [PREFETCH_CNT_BW-1:0]   sts_prefetch_cnt,
output                                      sts_fifo_full,
output                                      sts_fifo_afull,
output                                      sts_fifo_empty,
output                                      sts_fifo_aempty,

output                                      err_fifo_wilf,
output                                      err_fifo_wof,
output                                      err_fifo_rilf,
output                                      err_fifo_ruf
);

//################################################################################
// define local varialbe and localparam
//################################################################################


//################################################################################
// main
//################################################################################

generate if (CPU_DOMAIN=="CLK_WR") begin:G_CLK_WR
    wire                                        aempty_th_busy_nc;
    wire                                        rilf_rdy_nc;
    wire                                        ruf_rdy_nc;

    assign fifo_afull_th = cfg_fifo_afull_th;
    
    sync_vect #(
        .VECT_BW                        (ADDR_BW                        ),
        .VECT_INI                       ({ADDR_BW{1'b0}}                ),
        .SYNC_NUM_D2S                   (SYNC_NUM_R2W                   ),
        .SYNC_NUM_S2D                   (SYNC_NUM_W2R                   )
    ) u_aempty_th ( 
        .rst_src_n                      (rst_wr_n                       ),
        .clk_src                        (clk_wr                         ),

        .src_pause                      (1'b0                           ),	// keep src_pause 1'b0 as far as possible for robustness
        .src_vect                       (cfg_fifo_aempty_th             ),
        .src_busy                       (aempty_th_busy_nc              ),	// last vect is uncompleted

        .rst_dst_n                      (rst_rd_n                       ),
        .clk_dst                        (clk_rd                         ),

        .dst_vect                       (fifo_aempty_th                 )
    );
    
    assign sts_fifo_cnt = fifo_wcnt;

    if (PREFETCH_CNT_BW==1) begin:PCNT_SB
        sync_dff #(
            .SYNC_NUM                       (SYNC_NUM_R2W                   ),	// synchronization pipeline number for each bit
            .BW                             (1                              ),	// bit width
            .INI                            (1'b0                           )
        ) u_prefetch_cnt ( 
            .rst_n                          (rst_wr_n                       ),
            .clk                            (clk_wr                         ),

            .d                              (prefetch_cnt                   ),	// based on raw clock domain, forbid combinational logic input
            .q                              (sts_prefetch_cnt               )	// based on clk domain, synchronization is completed
        );
    end else begin:PCNT_MB
        wire                                        prefetch_cnt_busy_nc;

        sync_vect #(
            .VECT_BW                        (PREFETCH_CNT_BW                ),
            .VECT_INI                       ({PREFETCH_CNT_BW{1'b0}}        ),
            .SYNC_NUM_D2S                   (SYNC_NUM_W2R                   ),
            .SYNC_NUM_S2D                   (SYNC_NUM_R2W                   )
        ) u_prefetch_cnt ( 
            .rst_src_n                      (rst_rd_n                       ),
            .clk_src                        (clk_rd                         ),

            .src_pause                      (1'b0                           ),	// keep src_pause 1'b0 as far as possible for robustness
            .src_vect                       (prefetch_cnt                   ),
            .src_busy                       (prefetch_cnt_busy_nc           ),	// last vect is uncompleted

            .rst_dst_n                      (rst_wr_n                       ),
            .clk_dst                        (clk_wr                         ),

            .dst_vect                       (sts_prefetch_cnt               )
        );
    end

    assign sts_fifo_full  = fifo_full;
    assign sts_fifo_afull = fifo_afull;

    sync_dff #(
        .SYNC_NUM                       (SYNC_NUM_R2W                   ),	// synchronization pipeline number for each bit
        .BW                             (2                              ),	// bit width
        .INI                            (2'b11                          )
    ) u_empty ( 
        .rst_n                          (rst_wr_n                       ),
        .clk                            (clk_wr                         ),

        .d                              ({    fifo_empty,     fifo_aempty}  ),
        .q                              ({sts_fifo_empty, sts_fifo_aempty}  )
    );

    assign err_fifo_wilf = fifo_wilf;
    assign err_fifo_wof  = fifo_wof;

    sync_pls #(
        .CNT_BW                         (0                              ),	// the max number of uncompleted pulse is 2^CNT_BW
        .SYNC_NUM_D2S                   (SYNC_NUM_W2R                   ),	// min gap between two transmission about SYNC_NUM_D2S+SYNC_NUM_S2D+2 clock steps
        .SYNC_NUM_S2D                   (SYNC_NUM_R2W                   )
    ) u_rilf ( 
        .rst_src_n                      (rst_rd_n                       ),
        .clk_src                        (clk_rd                         ),

        .src_pls                        (fifo_rilf                      ),	// keep src_pls 1'b1 when src_rdy 1'b0 unless missing pulse make no difference to system
        .src_rdy                        (rilf_rdy_nc                    ),	// ignore src_rdy and set MISS_PLS_CHKEN

        .rst_dst_n                      (rst_wr_n                       ),
        .clk_dst                        (clk_wr                         ),

        .dst_pls                        (err_fifo_rilf                  ),
        .dst_rdy                        (1'b1                           )
    );

    sync_pls #(
        .CNT_BW                         (0                              ),	// the max number of uncompleted pulse is 2^CNT_BW
        .SYNC_NUM_D2S                   (SYNC_NUM_W2R                   ),	// min gap between two transmission about SYNC_NUM_D2S+SYNC_NUM_S2D+2 clock steps
        .SYNC_NUM_S2D                   (SYNC_NUM_R2W                   )
    ) u_ruf  ( 
        .rst_src_n                      (rst_rd_n                       ),
        .clk_src                        (clk_rd                         ),

        .src_pls                        (fifo_ruf                       ),	// keep src_pls 1'b1 when src_rdy 1'b0 unless missing pulse make no difference to system
        .src_rdy                        (ruf_rdy_nc                     ),	// ignore src_rdy and set MISS_PLS_CHKEN

        .rst_dst_n                      (rst_wr_n                       ),
        .clk_dst                        (clk_wr                         ),

        .dst_pls                        (err_fifo_ruf                   ),
        .dst_rdy                        (1'b1                           )
    );

end else if (CPU_DOMAIN=="CLK_RD") begin:G_CLK_RD
    wire                                        afull_th_busy_nc;
    wire                                        wilf_rdy_nc;
    wire                                        wof_rdy_nc;
    
    assign fifo_aempty_th = cfg_fifo_aempty_th;
    
    sync_vect #(
        .VECT_BW                        (ADDR_BW                        ),
        .VECT_INI                       ({ADDR_BW{1'b0}}                ),
        .SYNC_NUM_D2S                   (SYNC_NUM_W2R                   ),
        .SYNC_NUM_S2D                   (SYNC_NUM_R2W                   )
    ) u_afull_th ( 
        .rst_src_n                      (rst_rd_n                       ),
        .clk_src                        (clk_rd                         ),

        .src_pause                      (1'b0                           ),	// keep src_pause 1'b0 as far as possible for robustness
        .src_vect                       (cfg_fifo_afull_th              ),
        .src_busy                       (afull_th_busy_nc               ),	// last vect is uncompleted

        .rst_dst_n                      (rst_wr_n                       ),
        .clk_dst                        (clk_wr                         ),

        .dst_vect                       (fifo_afull_th                  )
    );
    
    assign sts_fifo_cnt = fifo_rcnt;
    assign sts_prefetch_cnt = prefetch_cnt;

    assign sts_fifo_empty  = fifo_empty;
    assign sts_fifo_aempty = fifo_aempty;

    sync_dff #(
        .SYNC_NUM                       (SYNC_NUM_W2R                   ),	// synchronization pipeline number for each bit
        .BW                             (2                              ),	// bit width
        .INI                            (2'b00                          )
    ) u_full ( 
        .rst_n                          (rst_rd_n                       ),
        .clk                            (clk_rd                         ),

        .d                              ({    fifo_full,     fifo_afull}),
        .q                              ({sts_fifo_full, sts_fifo_afull})
    );

    assign err_fifo_rilf = fifo_rilf;
    assign err_fifo_ruf  = fifo_ruf;

    sync_pls #(
        .CNT_BW                         (0                              ),	// the max number of uncompleted pulse is 2^CNT_BW
        .SYNC_NUM_D2S                   (SYNC_NUM_R2W                   ),	// min gap between two transmission about SYNC_NUM_D2S+SYNC_NUM_S2D+2 clock steps
        .SYNC_NUM_S2D                   (SYNC_NUM_W2R                   )
    ) u_wilf ( 
        .rst_src_n                      (rst_wr_n                       ),
        .clk_src                        (clk_wr                         ),

        .src_pls                        (fifo_wilf                      ),	// keep src_pls 1'b1 when src_rdy 1'b0 unless missing pulse make no difference to system
        .src_rdy                        (wilf_rdy_nc                    ),	// ignore src_rdy and set MISS_PLS_CHKEN

        .rst_dst_n                      (rst_rd_n                       ),
        .clk_dst                        (clk_rd                         ),

        .dst_pls                        (err_fifo_wilf                  ),
        .dst_rdy                        (1'b1                           )
    );

    sync_pls #(
        .CNT_BW                         (0                              ),	// the max number of uncompleted pulse is 2^CNT_BW
        .SYNC_NUM_D2S                   (SYNC_NUM_R2W                   ),	// min gap between two transmission about SYNC_NUM_D2S+SYNC_NUM_S2D+2 clock steps
        .SYNC_NUM_S2D                   (SYNC_NUM_W2R                   )
    ) u_wof  ( 
        .rst_src_n                      (rst_wr_n                       ),
        .clk_src                        (clk_wr                         ),

        .src_pls                        (fifo_wof                       ),	// keep src_pls 1'b1 when src_rdy 1'b0 unless missing pulse make no difference to system
        .src_rdy                        (wof_rdy_nc                     ),	// ignore src_rdy and set MISS_PLS_CHKEN

        .rst_dst_n                      (rst_rd_n                       ),
        .clk_dst                        (clk_rd                         ),

        .dst_pls                        (err_fifo_wof                   ),
        .dst_rdy                        (1'b1                           )
    );
end endgenerate

//################################################################################
// ASSERTION
//################################################################################

`ifdef CBB_ASSERT_ON
// synopsys translate_off

generate if (CPU_DOMAIN=="CLK_WR") begin:A_CLK_WR

    initial begin
        G_CLK_WR.u_rilf.MISS_PLS_CHKEN = 1'b0;
        G_CLK_WR.u_ruf.MISS_PLS_CHKEN = 1'b0;
    end

end else if (CPU_DOMAIN=="CLK_RD") begin:A_CLK_RD

    initial begin
        G_CLK_RD.u_wilf.MISS_PLS_CHKEN = 1'b0;
        G_CLK_RD.u_wof.MISS_PLS_CHKEN = 1'b0;
    end

end endgenerate

// synopsys translate_on
`endif

endmodule
